#ifndef __BUOLA_SCENE_CVERTEXDATA_H__
#define __BUOLA_SCENE_CVERTEXDATA_H__

#include <buola/scene.h>
#include <buola/gl.h>

namespace buola { namespace scene {

template<typename tType>
struct MGLType;

template<>
struct MGLType<float>
{
    static const GLenum mType=GL_FLOAT;
};

template<>
struct MGLType<uint32_t>
{
    static const GLenum mType=GL_UNSIGNED_INT;
};
    
class CVertexData
{
    struct SField
    {
        std::string mName;                  //!< (optional) field name
        EFieldSemanticType mSemanticType;   //!< e.g. FIELD_POSITION or FIELD_NORMAL
        GLenum mDataType;
        int mElementSize;                   //!< size of one element in the field
        int mCount;                         //!< number of elements in the field
        int mFieldSize;                     //!< size of the field (=mElementSize*mCount+padding)
        int mOffset;                        //!< offset from the beginning of a record
    };

public:
    CVertexData();
    ~CVertexData();

public:
    template<typename tType>
    void AddField(EFieldSemanticType pSemanticType,int pCount,const std::string &pName=std::string())
    {
        DoAddField(pSemanticType,MGLType<tType>::mType,sizeof(tType),pCount,pName);
    }

    int GetVertexSize()     {   return mVertexSize;     }
    int GetVertexCount()    {   return mVertexCount;    }

    void Resize(int pCount);

    void *Map(GLenum pType=GL_WRITE_ONLY);

    template<typename tType>
    tType *Map(GLenum pType=GL_WRITE_ONLY)
    {
        assert(sizeof(tType)==mVertexSize);
        return reinterpret_cast<tType*>(Map(pType));
    }
    
    void Unmap();

    GLuint GetVBO() {   return mVBO;    }
    
    void SetVertexAttrib(int pIndex,EFieldSemanticType pType);
    
    explicit operator bool()    {   return mVBO!=0; }
    
private:
    void DoAddField(EFieldSemanticType pSemanticType,GLenum pDataType,int pElementSize,
                    int pCount,const std::string &pName);
    
private:
    GLuint mVBO;
    std::vector<SField*> mFields;
    int mVertexSize;
//    int mVertexCapacity;
    int mVertexCount;
};

/*namespace scene*/ } /*namespace buola*/ }

#endif
